package com.cloudbroker.bcs.common.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BeanUtil {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(BeanUtil.class);
    
    private static Field findField(Object bean, String fieldName) {
        if (null == fieldName) {
            return null;
        }
        try {
            Class<?> clazz = bean.getClass();
            do {
                Field[] fields = clazz.getDeclaredFields();
                int len = fields.length;
                for (int i = 0; i < len; i++) {
                    Field field = fields[i];
                    if (fieldName.equals(field.getName())) {
                        return field;
                    }
                }
            } while (null != (clazz = clazz.getSuperclass()));
        } catch (Exception e) {
            // 不打印bean，万一有敏感数据
            LOGGER.error("find field failed, beanClass=" + bean.getClass() + ", fieldName=" + fieldName, e);
        }
        return null;
    }
    
    public static Object getFieldValue(Object bean, String fieldName) {
        Field field = findField(bean, fieldName);
        if (null != field) {
            try {
                ReflectionUtil.makeAccessible(field);
                return field.get(bean);
            } catch (Exception e) {
                // 不打印bean，万一有敏感数据
                LOGGER.error("get field value failed, beanClass=" + bean.getClass() + ", fieldName=" + fieldName, e);
            }
        }
        return null;
    }
    
    public static void setFieldValue(Object bean, String fieldName, Object fieldValue) {
        Field field = findField(bean, fieldName);
        if (null != field) {
            try {
                ReflectionUtil.makeAccessible(field);
                field.set(bean, fieldValue);
            } catch (Exception e) {
                // 不打印bean，万一有敏感数据
                LOGGER.error("get field value failed, beanClass=" + bean.getClass() + ", fieldName=" + fieldName, e);
            }
        }
    }
    
    public static Object getProperty(Object bean, String propertyName, boolean tryField) {
        try {
            PropertyDescriptor propertyDescriptor = findPropertyDescriptor(bean, propertyName);
            if (null == propertyDescriptor) {
                if (tryField) {
                    return getFieldValue(bean, propertyName);
                }
            } else {
                return propertyDescriptor.getReadMethod().invoke(bean);
            }
        } catch (Exception e) {
            // 不打印bean，万一有敏感数据
            LOGGER.error("read property failed, beanClass=" + bean.getClass() + ", propertyName=" + propertyName, e);
        }
        return null;
    }
    
    public static void setProperty(Object bean, String propertyName, Object propertyValue, boolean tryField) {
        try {
            PropertyDescriptor propertyDescriptor = findPropertyDescriptor(bean, propertyName);
            if (null == propertyDescriptor) {
                if (tryField) {
                    setFieldValue(bean, propertyName, propertyValue);
                }
            } else {
                propertyDescriptor.getWriteMethod().invoke(bean, propertyValue);
            }
        } catch (Exception e) {
            // 不打印bean，万一有敏感数据
            LOGGER.error("set property failed, beanClass=" + bean.getClass() + ", propertyName=" + propertyName, e);
        }
    }
    
    public static Object getProperty(Object bean, String propertyName) {
        return getProperty(bean, propertyName, false);
    }
    
    public static void setProperty(Object bean, String propertyName, Object propertyValue) {
        setProperty(bean, propertyName, propertyValue, false);
    }
    
    private static PropertyDescriptor findPropertyDescriptor(Object bean, String propertyName) {
        try {
            if (null == bean || StringUtils.isBlank(propertyName)) {
                return null;
            }
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                if (propertyName.equals(propertyDescriptor.getName())) {
                    return propertyDescriptor;
                }
            }
        } catch (Exception e) {
            // 不打印bean，万一有敏感数据
            LOGGER.error("find bean property failed, beanClass=" + bean.getClass() + ", propertyName="
                    + propertyName, e);
        }
        // 找不到对应的属性则返回null
        return null;
    }
    
}
